/* 
 * File:   Engine.cpp
 * Author: ferranferri
 * 
 * Created on May 29, 2013, 5:39 PM
 */

#include "Engine.h"
#include "graphics/internal/engine_constants.h"
#include "utils/cuUtils.h"
#include "vfs/vfs.h"


namespace z3d{
    Engine::Engine()
        :_properties(NULL)
        ,_log(NULL)
        ,_isRunning(false)
        ,_vfs(NULL)
    {
        glog::CGlobalLog::initSingleton();
    }

    bool Engine::init(const std::string& properties) {

        try{
            initLog();
            initProperties(properties);
            initWindow();
            initVFS();
        }catch(z3d::core::Z3D_Base_Exception& e)
        {
            _log->processMessages();
            return false;
        }
        return true;
    }

    const std::string Engine::updateClientVersion() {
        std::stringstream ss;
        z3d::utils::Properties* version = _properties->getChild("client_version");
        if(version == NULL) {
            THROW_AND_LOG(Z3D_APPENDER,z3d::core::resourceIncorrectFormatException, "\"Client_version\" key was not found");
            return "";
        }
        
        ss      << version->getPropertyAsUnsigned("major", 0) << "." 
                << version->getPropertyAsUnsigned("minor", 0) << "."
                << version->getPropertyAsUnsigned("revision", 0);

        delete version;
        return ss.str();
    }
    
    bool Engine::isRunning() {
        return _window.isOpen();
    }
    
    bool Engine::update() {
        _window.render();
        return true;
    }
    
    bool Engine::initLog() {
        // iniciar log principal (este debe ser quien primero inicia el singleton del log)
        _log = &glog::CGlobalLog::getSingleton();
        #ifdef _DEBUG
            boost::shared_ptr<glog::IListener> myLogListener(new glog::CLogWriter("engine_log_debug.txt", glog::LOGLEVEL_DEBUG));
        #else
            // TODO: asegurarse de poner esta linea en el estado correcto de debug
            boost::shared_ptr<glog::IListener> myLogListener(new glog::CLogWriter("engine_log.txt", glog::LOGLEVEL_DEBUG));
        #endif //_DEBUG
        _log->addListener(myLogListener, Z3D_APPENDER);
        _log->addListener(myLogListener, UTILS_APPENDER);
        _log->INFO_MSG(Z3D_APPENDER, "Starting engine Zeleste ....");
        _log->INFO_MSG(Z3D_APPENDER, "=================================");
        _log->processMessages();
        return true;
    }
    
    bool Engine::initProperties(const std::string& properties) {
       // cargar propiedades del sistema
        _properties = new z3d::utils::Properties(properties, false);
        if(!_properties->processFile()) {
            _log->ERROR_MSG(Z3D_APPENDER, "Cannot open properties file \"%s\"", properties.c_str());
            return false;
        }
        _log->INFO_MSG(Z3D_APPENDER, "Zeleste engine version %s", updateClientVersion().c_str()); 
        return true;
    }
    
    bool Engine::initWindow() {
        // crear el objeto window
        if(!_window.init())
            THROW_AND_LOG(Z3D_APPENDER, z3d::core::Z3DRuntimeException, "Error initializing window");
        try{
            z3d::utils::Properties* prop = _properties->getChild("window");
            if(prop == NULL) {
                THROW_AND_LOG(Z3D_APPENDER, z3d::core::resourceIncorrectFormatException, "The properties file has not a \"window\" property");
            }
            // extraer propiedades
            uint32_t width = prop->getPropertyAsUnsigned("width", 640);
            uint32_t height = prop->getPropertyAsUnsigned("height", 400);
            uint32_t bpp = prop->getPropertyAsUnsigned("bpp", 640);
            std::string title = prop->getPropertyAsString("title", "No title");
            bool fullscreen = prop->getPropertyAsBoolean("fullscreen", false);
            _window.open(width, height, bpp, fullscreen, title);
        }
        catch(std::exception e){
            THROW_AND_LOG(Z3D_APPENDER, z3d::core::Z3DRuntimeException, "Cannot open window.");
            return false;
        }
        return true;
    }
    
    bool Engine::initVFS() {
        _vfs = new z3d::utils::CVirtualFileSystem();
        _vfs->init();
        
        z3d::utils::Properties* prop = _properties->getChild("vfs");
        if(prop == NULL) {
            THROW_AND_LOG(Z3D_APPENDER, z3d::core::resourceIncorrectFormatException, "The properties file has not a \"vfs\" property");
        }
        

        std::string rootPath = prop->getPropertyAsString("root", "./");
        std::string writePath = prop->getPropertyAsString("writePath", "./tmp/");

        _vfs->setSystemResourcesBasePath(rootPath.c_str());
        _vfs->setWriteDirectory(writePath.c_str());
        delete prop;
        return true;
    }
    
    bool Engine::shutDown() {
        _log->processMessages();
        _window.close();
        return true;
    }
    
    Engine::~Engine() {
        _log->DEBUG_MSG(Z3D_APPENDER, "Destroying objects...");
        delete _properties;
        _vfs->reset();
        delete _vfs;
        _log->processMessages();
        _log->destroySingleton();
    }
}
